<?php

/*
    CVS Revision. 1.1.0
*/

class FastTemplate {

    var $FILELIST   =   array();    //  Holds the array of filehandles
                                    //  FILELIST[HANDLE] == "fileName"

    var $DYNAMIC    =   array();    //  Holds the array of dynamic
                                    //  blocks, and the fileHandles they
                                    //  live in.

    var $PARSEVARS  =   array();    //  Holds the array of Variable
                                    //  handles.
                                    //  PARSEVARS[HANDLE] == "value"

    var $LOADED     =   array();    //  We only want to load a template
                                    //  once - when it's used.
                                    //  LOADED[FILEHANDLE] == 1 if loaded
                                    //  undefined if not loaded yet.

    var $HANDLE     =   array();    //  Holds the handle names assigned
                                    //  by a call to parse()

    var $ROOT       =   "";         //  Holds path-to-templates

    var $WIN32      =   false;      //  Set to true if this is a WIN32 server

    var $ERROR      =   "";         //  Holds the last error message

    var $LAST       =   "";         //  Holds the HANDLE to the last
                                    //  template parsed by parse()

    var $STRICT     =   true;       //  Strict template checking.
                                    //  Unresolved vars in templates will
                                    //  generate a warning when found.

//  ************************************************************

    function FastTemplate ($pathToTemplates = "")
    {
        global $php_errormsg;

        if(!empty($pathToTemplates))
        {
            $this->set_root($pathToTemplates);
        }

    }   // end (new) FastTemplate ()


//  ************************************************************
//  All templates will be loaded from this "root" directory
//  Can be changed in mid-process by re-calling with a new
//  value.

    function set_root ($root)
    {
        $trailer = substr($root,-1);

        if(!$this->WIN32)
        {
            if( (ord($trailer)) != 47 )
            {
                $root = "$root". chr(47);
            }

            if(is_dir($root))
            {
                $this->ROOT = $root;
            }
            else
            {
                $this->ROOT = "";
                $this->error("Specified ROOT dir [$root] is not a directory");
            }
        }
        else
        {
            // WIN32 box - no testing
            if( (ord($trailer)) != 92 )
            {
                $root = "$root" . chr(92);
            }
            $this->ROOT = $root;
        }

    }   // End set_root()


//  **************************************************************
//  Calculates current microtime
//  I throw this into all my classes for benchmarking purposes
//  It's not used by anything in this class and can be removed
//  if you don't need it.


    function utime ()
    {
        $time = explode( " ", microtime());
        $usec = (double)$time[0];
        $sec = (double)$time[1];
        return $sec + $usec;
    }

//  **************************************************************
//  Strict template checking, if true sends warnings to STDOUT when
//  parsing a template with undefined variable references
//  Used for tracking down bugs-n-such. Use no_strict() to disable.

    function strict ()
    {
        $this->STRICT = true;
    }

//  ************************************************************
//  Silently discards (removes) undefined variable references
//  found in templates

    function no_strict ()
    {
        $this->STRICT = false;
    }

//  ************************************************************
//  A quick check of the template file before reading it.
//  This is -not- a reliable check, mostly due to inconsistencies
//  in the way PHP determines if a file is readable.

    function is_safe ($filename)
    {
        if(!file_exists($filename))
        {
            $this->error("[$filename] does not exist",0);
            return false;
        }
        return true;
    }

//  ************************************************************
//  Grabs a template from the root dir and 
//  reads it into a (potentially REALLY) big string

    function get_template ($template)
    {
        if(empty($this->ROOT))
        {
            $this->error("Cannot open template. Root not valid.",1);
            return false;
        }

        $filename   =   "$this->ROOT"."$template";

        $contents = implode("",(@file($filename)));
        if( (!$contents) or (empty($contents)) )
        {
            $this->error("get_template() failure: [$filename] $php_errormsg",1);
        }

        return $contents;

    } // end get_template

//  ************************************************************
//  Prints the warnings for unresolved variable references
//  in template files. Used if STRICT is true

    function show_unknowns ($Line)
    {
        $unknown = array();
        if (ereg("({[A-Z0-9_]+})",$Line,$unknown))
        {
            $UnkVar = $unknown[1];
            if(!(empty($UnkVar)))
            {
                @error_log("[FastTemplate] Warning: no value found for variable: $UnkVar ",0);
            }
        }
    }   // end show_unknowns()

//  ************************************************************
//  This routine get's called by parse() and does the actual
//  {VAR} to VALUE conversion within the template.

    function parse_template ($template, $tpl_array)
    {
        while ( list ($key,$val) = each ($tpl_array) )
        {
            if (!(empty($key)))
            {
                if(gettype($val) != "string")
                {
                    settype($val,"string");
                }

                #$template = ereg_replace("{$key}","$val","$template");
                #//$template = str_replace("{$key}","$val","$template");
                $key = '{'."$key".'}';
                $template = ereg_replace("$key","$val","$template");
                //$template = str_replace("$key","$val","$template");
            }
        }

        if(!$this->STRICT)
        {
            // Silently remove anything not already found

            $template = ereg_replace("{([A-Z0-9_]+)}","",$template);
        }
        else
        {
            // Warn about unresolved template variables
            if (ereg("({[A-Z0-9_]+})",$template))
            {
                $unknown = split("\n",$template);
                while (list ($Element,$Line) = each($unknown) )
                {
                    $UnkVar = $Line;
                    if(!(empty($UnkVar)))
                    {
                        $this->show_unknowns($UnkVar);
                    }
                }
            }
        }
        return $template;

    }   // end parse_template();

//  ************************************************************
//  The meat of the whole class. The magic happens here.

    function parse ( $ReturnVar, $FileTags )
    {
        $append = false;
        $this->LAST = $ReturnVar;
        $this->HANDLE[$ReturnVar] = 1;

        if (gettype($FileTags) == "array")
        {
            unset($this->$ReturnVar);   // Clear any previous data

            while ( list ( $key , $val ) = each ( $FileTags ) )
            {
                if ( (!isset($this->$val)) || (empty($this->$val)) )
                {
                    $this->LOADED["$val"] = 1;
                    if(isset($this->DYNAMIC["$val"]))
                    {
                        $this->parse_dynamic($val,$ReturnVar);
                    }
                    else
                    {
                        $fileName = $this->FILELIST["$val"];
                        $this->$val = $this->get_template($fileName);
                    }
                }

                //  Array context implies overwrite

                $this->$ReturnVar = $this->parse_template($this->$val,$this->PARSEVARS);

                //  For recursive calls.

                $this->assign( array( $ReturnVar => $this->$ReturnVar ) );

            }
        }   // end if FileTags is array()
        else
        {
            // FileTags is not an array

            $val = $FileTags;

            if( (substr($val,0,1)) == '.' )
            {
                // Append this template to a previous ReturnVar

                $append = true;
                $val = substr($val,1);
            }

            if ( (!isset($this->$val)) || (empty($this->$val)) )
            {
                    $this->LOADED["$val"] = 1;
                    if(isset($this->DYNAMIC["$val"]))
                    {
                        $this->parse_dynamic($val,$ReturnVar);
                    }
                    else
                    {
                        $fileName = $this->FILELIST["$val"];
                        $this->$val = $this->get_template($fileName);
                    }
            }

            if($append)
            {
                $this->$ReturnVar .= $this->parse_template($this->$val,$this->PARSEVARS);
            }
            else
            {
                $this->$ReturnVar = $this->parse_template($this->$val,$this->PARSEVARS);
            }

            //  For recursive calls.

            $this->assign(array( $ReturnVar => $this->$ReturnVar) );

        }
        return;
    }   //  End parse()


//  ************************************************************

    function FastPrint ( $template = "" )
    {
        if(empty($template))
        {
            $template = $this->LAST;
        }

        if( (!(isset($this->$template))) || (empty($this->$template)) )
        {
            $this->error("Nothing parsed, nothing printed",0);
            return;
        }
        else
        {
            print $this->$template;
        }
        return;
    }

//  ************************************************************

    function fetch ( $template = "" )
    {
        if(empty($template))
        {
            $template = $this->LAST;
        }
        if( (!(isset($this->$template))) || (empty($this->$template)) )
        {
            $this->error("Nothing parsed, nothing printed",0);
            return "";
        }

        return($this->$template);
    }


//  ************************************************************

    function define_dynamic ($Macro, $ParentName)
    {
        //  A dynamic block lives inside another template file.
        //  It will be stripped from the template when parsed
        //  and replaced with the {$Tag}.

        $this->DYNAMIC["$Macro"] = $ParentName;
        return true;
    }

//  ************************************************************

    function parse_dynamic ($Macro,$MacroName)
    {
        // The file must already be in memory.

        $ParentTag = $this->DYNAMIC["$Macro"];
        if( (!$this->$ParentTag) or (empty($this->$ParentTag)) )
        {
            $fileName = $this->FILELIST[$ParentTag];
            $this->$ParentTag = $this->get_template($fileName);
            $this->LOADED[$ParentTag] = 1;
        }
        if($this->$ParentTag)
        {
            $template = $this->$ParentTag;
            $DataArray = split("\n",$template);
            $newMacro = "";
            $newParent = "";
            $outside = true;
            $start = false;
            $end = false;
            while ( list ($lineNum,$lineData) = each ($DataArray) )
            {
                $lineTest = trim($lineData);
                if("<!-- BEGIN DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
                {
                    $start = true;
                    $end = false;
                    $outside = false;
                }
                if("<!-- END DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
                {
                    $start = false;
                    $end = true;
                    $outside = true;
                }
                if( (!$outside) and (!$start) and (!$end) )
                {
                    $newMacro .= "$lineData\n"; // Restore linebreaks
                }
                if( ($outside) and (!$start) and (!$end) )
                {
                    $newParent .= "$lineData\n"; // Restore linebreaks
                }
                if($end)
                {
                    #$newParent .= "{$MacroName}\n";
                    $newParent .= '{'."$MacroName}\n";
                }
                // Next line please
                if($end) { $end = false; }
                if($start) { $start = false; }
            }   // end While

            $this->$Macro = $newMacro;
            $this->$ParentTag = $newParent;
            return true;

        }   // $ParentTag NOT loaded - MAJOR oopsie
        else
        {
            @error_log("ParentTag: [$ParentTag] not loaded!",0);
            $this->error("ParentTag: [$ParentTag] not loaded!",0);
        }
        return false;
    }

//  ************************************************************
//  Strips a DYNAMIC BLOCK from a template.

    function clear_dynamic ($Macro="")
    {
        if(empty($Macro)) { return false; }

        // The file must already be in memory.

        $ParentTag = $this->DYNAMIC["$Macro"];

        if( (!$this->$ParentTag) or (empty($this->$ParentTag)) )
        {
            $fileName = $this->FILELIST[$ParentTag];
            $this->$ParentTag = $this->get_template($fileName);
            $this->LOADED[$ParentTag] = 1;
        }

        if($this->$ParentTag)
        {
            $template = $this->$ParentTag;
            $DataArray = split("\n",$template);
            $newParent = "";
            $outside = true;
            $start = false;
            $end = false;
            while ( list ($lineNum,$lineData) = each ($DataArray) )
            {
                $lineTest = trim($lineData);
                if("<!-- BEGIN DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
                {
                    $start = true;
                    $end = false;
                    $outside = false;
                }
                if("<!-- END DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
                {
                    $start = false;
                    $end = true;
                    $outside = true;
                }
                if( ($outside) and (!$start) and (!$end) )
                {
                    $newParent .= "$lineData\n"; // Restore linebreaks
                }
                // Next line please
                if($end) { $end = false; }
                if($start) { $start = false; }
            }   // end While

            $this->$ParentTag = $newParent;
            return true;

        }   // $ParentTag NOT loaded - MAJOR oopsie
        else
        {
            @error_log("ParentTag: [$ParentTag] not loaded!",0);
            $this->error("ParentTag: [$ParentTag] not loaded!",0);
        }
        return false;
    }


//  ************************************************************

    function define ($fileList)
    {
        while ( list ($FileTag,$FileName) = each ($fileList) )
        {
            $this->FILELIST["$FileTag"] = $FileName;
        }
        return true;
    }

//  ************************************************************

    function clear_parse ( $ReturnVar = "")
    {
        $this->clear($ReturnVar);
    }

//  ************************************************************

    function clear ( $ReturnVar = "" )
    {
        // Clears out hash created by call to parse()

        if(!empty($ReturnVar))
        {
            if( (gettype($ReturnVar)) != "array")
            {
                unset($this->$ReturnVar);
                return;
            }
            else
            {
                while ( list ($key,$val) = each ($ReturnVar) )
                {
                    unset($this->$val);
                }
                return;
            }
        }

        // Empty - clear all of them

        while ( list ( $key,$val) = each ($this->HANDLE) )
        {
            $KEY = $key;
            unset($this->$KEY);
        }
        return;

    }   //  end clear()

//  ************************************************************

    function clear_all ()
    {
        $this->clear();
        $this->clear_assign();
        $this->clear_define();
        $this->clear_tpl();

        return;

    }   //  end clear_all

//  ************************************************************

    function clear_tpl ($fileHandle = "")
    {
        if(empty($this->LOADED))
        {
            // Nothing loaded, nothing to clear

            return true;
        }
        if(empty($fileHandle))
        {
            // Clear ALL fileHandles

            while ( list ($key, $val) = each ($this->LOADED) )
            {
                unset($this->$key);
            }
            unset($this->LOADED);

            return true;
        }
        else
        {
            if( (gettype($fileHandle)) != "array")
            {
                if( (isset($this->$fileHandle)) || (!empty($this->$fileHandle)) )
                {
                    unset($this->LOADED[$fileHandle]);
                    unset($this->$fileHandle);
                    return true;
                }
            }
            else
            {
                while ( list ($Key, $Val) = each ($fileHandle) )
                {
                    unset($this->LOADED[$Key]);
                    unset($this->$Key);
                }
                return true;
            }
        }

        return false;

    }   // end clear_tpl

//  ************************************************************

    function clear_define ( $FileTag = "" )
    {
        if(empty($FileTag))
        {
            unset($this->FILELIST);
            return;
        }

        if( (gettype($Files)) != "array")
        {
            unset($this->FILELIST[$FileTag]);
            return;
        }
        else
        {
            while ( list ( $Tag, $Val) = each ($FileTag) )
            {
                unset($this->FILELIST[$Tag]);
            }
            return;
        }
    }

//  ************************************************************
//  Aliased function - used for compatibility with CGI::FastTemplate
/*
    function clear_parse ()
    {
        $this->clear_assign();
    }
*/
//  ************************************************************
//  Clears all variables set by assign()

    function clear_assign ()
    {
        if(!(empty($this->PARSEVARS)))
        {
            while(list($Ref,$Val) = each ($this->PARSEVARS) )
            {
                unset($this->PARSEVARS["$Ref"]);
            }
        }
    }

//  ************************************************************

    function clear_href ($href)
    {
        if(!empty($href))
        {
            if( (gettype($href)) != "array")
            {
                unset($this->PARSEVARS[$href]);
                return;
            }
            else
            {
                while (list ($Ref,$val) = each ($href) )
                {
                    unset($this->PARSEVARS[$Ref]);
                }
                return;
            }
        }
        else
        {
            // Empty - clear them all

            $this->clear_assign();
        }
        return;
    }

//  ************************************************************

    function assign ($tpl_array, $trailer="")
    {
        if(gettype($tpl_array) == "array")
        {
            while ( list ($key,$val) = each ($tpl_array) )
            {
                if (!(empty($key)))
                {
                    //  Empty values are allowed
                    //  Empty Keys are NOT

                    $this->PARSEVARS["$key"] = $val;
                }
            }
        }
        else
        {
            // Empty values are allowed in non-array context now.
            if (!empty($tpl_array))
            {
                $this->PARSEVARS["$tpl_array"] = $trailer;
            }
        }
    }

//  ************************************************************
//  Return the value of an assigned variable.
//  Christian Brandel cbrandel@gmx.de

    function get_assigned($tpl_name = "")
    {
        if(empty($tpl_name)) { return false; }
        if(isset($this->PARSEVARS["$tpl_name"]))
        {
            return ($this->PARSEVARS["$tpl_name"]);
        }
        else
        {
            return false;
        }
    }

//  ************************************************************

    function error ($errorMsg, $die = 0)
    {
        $this->ERROR = $errorMsg;
        echo "ERROR: $this->ERROR <BR> \n";
        if ($die == 1)
        {
            exit;
        }

        return;

    } // end error()


//  ************************************************************



//  ************************************************************

} // End class.FastTemplate.php

function Money( $inbuffer, $dolsign = 0)
{

    // Insert Comma (,) into each third digit of Money variable

    $buffer = sprintf("%0.2f", $inbuffer);
    if( strlen($buffer) > 6) {
       $thenumber = "";
       $decimal = substr( $buffer, strrpos($buffer, "."));
       $left = substr( $buffer, 0, strrpos($buffer, "."));
       while( strlen($left) > 3) {
          $thenumber = $thenumber . "," . substr($left, -3);
          $left = substr( $left, 0, strlen($left)-3);
       }
       $thenumber = $left . $thenumber . $decimal;
    }
    else
       $thenumber = $buffer;

    if( $dolsign != 0)
       $thenumber = "\$ $thenumber";

    return( $thenumber);    
}

   // Define Template Path
   // 

   #$template_path = '/home/httpd/html';

?>
